home *** CD-ROM | disk | FTP | other *** search
- #==============================================================================
- # Contains utility procedures for mega-widgets.
- #
- # Structure of the module:
- # - Namespace initialization
- # - Public utility procedures
- #
- # Copyright (c) 2000-2004 Csaba Nemethi (E-mail: csaba.nemethi@t-online.de)
- #==============================================================================
-
- package require Tcl 8
- package require Tk 8
-
- #
- # Namespace initialization
- # ========================
- #
-
- namespace eval mwutil {
- #
- # Public variables:
- #
- variable version 1.7
- variable library [file dirname [info script]]
-
- #
- # Public procedures:
- #
- namespace export wrongNumArgs defineKeyNav generateEvent \
- configure fullConfigOpt fullOpt enumOpts \
- setConfigVals configSubCmd attribSubCmd
- }
-
- #
- # Public utility procedures
- # =========================
- #
-
- #------------------------------------------------------------------------------
- # mwutil::wrongNumArgs
- #
- # Generates a "wrong # args" error message.
- #------------------------------------------------------------------------------
- proc mwutil::wrongNumArgs args {
- set optList {}
- foreach arg $args {
- lappend optList \"$arg\"
- }
- return -code error "wrong # args: should be [enumOpts $optList]"
- }
-
- #------------------------------------------------------------------------------
- # mwutil::defineKeyNav
- #
- # For a given mega-widget class, the procedure defines the binding tag
- # ${class}KeyNav as a partial replacement for "all", by substituting the
- # scripts bound to the events <Key-Tab>, <Shift-Key-Tab>, and <<PrevWindow>>
- # with new ones which propagate these events to the mega-widget of the given
- # class containing the widget to which the event was reported. (The event
- # <Shift-Key-Tab> was replaced with <<PrevWindow>> in Tk 8.3.0.) This tag is
- # designed to be inserted before "all" in the list of binding tags of a
- # descendant of a mega-widget of the specified class.
- #------------------------------------------------------------------------------
- proc mwutil::defineKeyNav class {
- foreach event {<Key-Tab> <Shift-Key-Tab> <<PrevWindow>>} {
- bind ${class}KeyNav $event \
- [list mwutil::generateEvent %W $class $event]
- }
- }
-
- #------------------------------------------------------------------------------
- # mwutil::generateEvent
- #
- # This procedure generates the given event for the mega-widget of the specified
- # class containing the widget w if that mega-widget is not the only widget
- # receiving the focus during keyboard traversal within its top-level widget.
- #------------------------------------------------------------------------------
- proc mwutil::generateEvent {w class event} {
- while {[string compare [winfo class $w] $class] != 0} {
- set w [winfo parent $w]
- }
-
- if {[string compare [tk_focusNext $w] $w] != 0} {
- focus $w ;# necessary on Windows
- event generate $w $event
- }
-
- return -code break ""
- }
-
- #------------------------------------------------------------------------------
- # mwutil::configure
- #
- # Configures the widget win by processing the command-line arguments specified
- # in optValPairs and, if the value of initialize is true, also those database
- # options that don't match any command-line arguments.
- #------------------------------------------------------------------------------
- proc mwutil::configure {win configSpecsName configValsName \
- configCmd optValPairs initialize} {
- upvar $configSpecsName configSpecs
- upvar $configValsName configVals
-
- #
- # Process the command-line arguments
- #
- set cmdLineOpts {}
- set savedVals {}
- set failed 0
- set count [llength $optValPairs]
- foreach {opt val} $optValPairs {
- if {[catch {fullConfigOpt $opt configSpecs} result] != 0} {
- set failed 1
- break
- }
- if {$count == 1} {
- set result "value for \"$opt\" missing"
- set failed 1
- break
- }
- set opt $result
- lappend cmdLineOpts $opt
- lappend savedVals $configVals($opt)
- if {[catch {eval $configCmd [list $win $opt $val]} result] != 0} {
- set failed 1
- break
- }
- incr count -2
- }
-
- if {$failed} {
- #
- # Restore the saved values
- #
- foreach opt $cmdLineOpts val $savedVals {
- eval $configCmd [list $win $opt $val]
- }
-
- return -code error $result
- }
-
- if {$initialize} {
- #
- # Process those configuration options that were not
- # given as command-line arguments; use the corresponding
- # values from the option database if available
- #
- foreach opt [lsort [array names configSpecs]] {
- if {[llength $configSpecs($opt)] == 1 ||
- [lsearch -exact $cmdLineOpts $opt] >= 0} {
- continue
- }
- set dbName [lindex $configSpecs($opt) 0]
- set dbClass [lindex $configSpecs($opt) 1]
- set dbValue [option get $win $dbName $dbClass]
- if {[string compare $dbValue ""] != 0} {
- if {[catch {
- eval $configCmd [list $win $opt $dbValue]
- } result] != 0} {
- return -code error $result
- }
- } else {
- set default [lindex $configSpecs($opt) 3]
- eval $configCmd [list $win $opt $default]
- }
- }
- }
-
- return ""
- }
-
- #------------------------------------------------------------------------------
- # mwutil::fullConfigOpt
- #
- # Returns the full configuration option corresponding to the possibly
- # abbreviated option opt.
- #------------------------------------------------------------------------------
- proc mwutil::fullConfigOpt {opt configSpecsName} {
- upvar $configSpecsName configSpecs
-
- if {[info exists configSpecs($opt)]} {
- if {[llength $configSpecs($opt)] == 1} {
- return $configSpecs($opt)
- } else {
- return $opt
- }
- }
-
- set optList [lsort [array names configSpecs]]
- set count 0
- foreach elem $optList {
- if {[string first $opt $elem] == 0} {
- incr count
- if {$count == 1} {
- set option $elem
- } else {
- break
- }
- }
- }
-
- switch $count {
- 0 {
- ### return -code error "unknown option \"$opt\""
- return -code error \
- "bad option \"$opt\": must be [enumOpts $optList]"
- }
-
- 1 {
- if {[llength $configSpecs($option)] == 1} {
- return $configSpecs($option)
- } else {
- return $option
- }
- }
-
- default {
- ### return -code error "unknown option \"$opt\""
- return -code error \
- "ambiguous option \"$opt\": must be [enumOpts $optList]"
- }
- }
- }
-
- #------------------------------------------------------------------------------
- # mwutil::fullOpt
- #
- # Returns the full option corresponding to the possibly abbreviated option opt.
- #------------------------------------------------------------------------------
- proc mwutil::fullOpt {kind opt optList} {
- if {[lsearch -exact $optList $opt] >= 0} {
- return $opt
- }
-
- set count 0
- foreach elem $optList {
- if {[string first $opt $elem] == 0} {
- incr count
- if {$count == 1} {
- set option $elem
- } else {
- break
- }
- }
- }
-
- switch $count {
- 0 {
- return -code error \
- "bad $kind \"$opt\": must be [enumOpts $optList]"
- }
-
- 1 {
- return $option
- }
-
- default {
- return -code error \
- "ambiguous $kind \"$opt\": must be [enumOpts $optList]"
- }
- }
- }
-
- #------------------------------------------------------------------------------
- # mwutil::enumOpts
- #
- # Returns a string consisting of the elements of the given list, separated by
- # commas and spaces.
- #------------------------------------------------------------------------------
- proc mwutil::enumOpts optList {
- set optCount [llength $optList]
- set n 1
- foreach opt $optList {
- if {$n == 1} {
- set str $opt
- } elseif {$n < $optCount} {
- append str ", $opt"
- } else {
- if {$optCount > 2} {
- append str ","
- }
- append str " or $opt"
- }
-
- incr n
- }
-
- return $str
- }
-
- #------------------------------------------------------------------------------
- # mwutil::setConfigVals
- #
- # Sets the elements of the array specified by configValsName to the values
- # returned by passing the widget name win and the relevant options to the
- # command given by cgetCmd.
- #------------------------------------------------------------------------------
- proc mwutil::setConfigVals {win configSpecsName configValsName
- cgetCmd argList} {
- upvar $configSpecsName configSpecs
- upvar $configValsName configVals
-
- set optList {}
- if {[llength $argList] == 0} {
- foreach opt [array names configSpecs] {
- if {[llength $configSpecs($opt)] > 1} {
- lappend optList $opt
- }
- }
- } else {
- foreach {opt val} $argList {
- lappend optList [fullConfigOpt $opt configSpecs]
- }
- }
-
- foreach opt $optList {
- set configVals($opt) [eval $cgetCmd [list $win $opt]]
- }
- }
-
- #------------------------------------------------------------------------------
- # mwutil::configSubCmd
- #
- # This procedure is invoked to process configuration subcommands.
- #------------------------------------------------------------------------------
- proc mwutil::configSubCmd {win configSpecsName configValsName
- configCmd argList} {
- upvar $configSpecsName configSpecs
- upvar $configValsName configVals
-
- switch [llength $argList] {
- 0 {
- #
- # Return a list describing all available configuration options
- #
- foreach opt [lsort [array names configSpecs]] {
- if {[llength $configSpecs($opt)] == 1} {
- set alias $configSpecs($opt)
- if {$::tk_version < 8.1} {
- set dbName [lindex $configSpecs($alias) 0]
- lappend result [list $opt $dbName]
- } else {
- lappend result [list $opt $alias]
- }
- } else {
- set dbName [lindex $configSpecs($opt) 0]
- set dbClass [lindex $configSpecs($opt) 1]
- set default [lindex $configSpecs($opt) 3]
- lappend result [list $opt $dbName $dbClass $default \
- $configVals($opt)]
- }
- }
- return $result
- }
-
- 1 {
- #
- # Return the description of the specified configuration option
- #
- set opt [fullConfigOpt [lindex $argList 0] configSpecs]
- set dbName [lindex $configSpecs($opt) 0]
- set dbClass [lindex $configSpecs($opt) 1]
- set default [lindex $configSpecs($opt) 3]
- return [list $opt $dbName $dbClass $default $configVals($opt)]
- }
-
- default {
- #
- # Set the specified configuration options to the given values
- #
- return [configure $win configSpecs configVals $configCmd $argList 0]
- }
- }
- }
-
- #------------------------------------------------------------------------------
- # mwutil::attribSubCmd
- #
- # This procedure is invoked to process the attrib subcommand.
- #------------------------------------------------------------------------------
- proc mwutil::attribSubCmd {win argList} {
- set classNs [string tolower [winfo class $win]]
- upvar ::${classNs}::ns${win}::attribVals attribVals
-
- set argCount [llength $argList]
- switch $argCount {
- 0 {
- #
- # Return the current list of attribute names and values
- #
- set result {}
- foreach attr [lsort [array names attribVals]] {
- lappend result [list $attr $attribVals($attr)]
- }
- return $result
- }
-
- 1 {
- #
- # Return the value of the specified attribute
- #
- set attr [lindex $argList 0]
- if {[info exists attribVals($attr)]} {
- return $attribVals($attr)
- } else {
- return ""
- }
- }
-
- default {
- #
- # Set the specified attributes to the given values
- #
- if {$argCount % 2 != 0} {
- return -code error "value for \"[lindex $argList end]\" missing"
- }
- array set attribVals $argList
- return ""
- }
- }
- }
-